using System;

namespace Com.FirstSolver.Splash;

public class FpPoint : ECPoint
{
	protected internal override bool YTilde => base.mY.ToBigInteger().TestBit(0);

	public FpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y)
		: this(curve, x, y, withCompression: false)
	{
	}

	public FpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
		: base(curve, x, y, withCompression)
	{
		if ((x != null && y == null) || (x == null && y != null))
		{
			throw new ArgumentException("Exactly one of the field elements is null");
		}
	}

	public override ECPoint Add(ECPoint b)
	{
		if (base.IsInfinity)
		{
			return b;
		}
		if (b.IsInfinity)
		{
			return this;
		}
		if (x.Equals(b.x))
		{
			if (y.Equals(b.y))
			{
				return Twice();
			}
			return curve.Infinity;
		}
		ECFieldElement gamma = b.y.Subtract(y).Divide(b.x.Subtract(x));
		ECFieldElement x3 = gamma.Square().Subtract(x).Subtract(b.x);
		ECFieldElement y3 = gamma.Multiply(x.Subtract(x3)).Subtract(y);
		return new FpPoint(curve, x3, y3);
	}

	public override ECPoint Twice()
	{
		if (base.IsInfinity)
		{
			return this;
		}
		if (y.ToBigInteger().SignValue == 0)
		{
			return curve.Infinity;
		}
		ECFieldElement TWO = curve.FromBigInteger(BigInteger.Two);
		ECFieldElement THREE = curve.FromBigInteger(BigInteger.Three);
		ECFieldElement gamma = x.Square().Multiply(THREE).Add(curve.mA)
			.Divide(y.Multiply(TWO));
		ECFieldElement x3 = gamma.Square().Subtract(x.Multiply(TWO));
		ECFieldElement y3 = gamma.Multiply(x.Subtract(x3)).Subtract(y);
		return new FpPoint(curve, x3, y3, withCompression);
	}

	public override ECPoint Subtract(ECPoint b)
	{
		if (b.IsInfinity)
		{
			return this;
		}
		return Add(b.Negate());
	}

	public override ECPoint Negate()
	{
		return new FpPoint(curve, x, y.Negate(), withCompression);
	}
}
